package comp.wxapi.service;

import java.io.File;
import java.io.FileReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.PublicKey;
import java.security.Security;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.github.binarywang.wxpay.bean.entpay.EntPayBankQueryRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayBankQueryResult;
import com.github.binarywang.wxpay.bean.entpay.EntPayBankRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayBankResult;
import com.github.binarywang.wxpay.bean.entpay.EntPayQueryRequest;
import com.github.binarywang.wxpay.bean.entpay.EntPayQueryResult;
import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult.ReqInfo;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayOrderCloseRequest;
import com.github.binarywang.wxpay.bean.request.WxPayOrderQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRedpackQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundQueryRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPaySendRedpackRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.bean.result.WxPayBillResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderCloseResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRedpackQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.bean.result.WxPaySendRedpackResult;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants.BillType;
import com.github.binarywang.wxpay.constant.WxPayConstants.SignType;
import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType;
import com.github.binarywang.wxpay.converter.WxPayOrderNotifyResultConverter;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.EntPayService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.EntPayServiceImpl;
import com.github.binarywang.wxpay.util.SignUtils;
import com.thoughtworks.xstream.XStream;

import comp.wxapi.bean.BaseConfigBean;
import comp.wxapi.bean.Result;
import comp.wxapi.constants.Constants;
import comp.wxapi.utils.IPUtils;
import comp.wxapi.utils.RequestUtils;
import comp.wxapi.utils.UUIDUtils;
import comp.wxapi.utils.XstreamUtils;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import weixin.popular.util.XMLConverUtil;

@Service
public class PayService extends WxAbstractBaseService {
	
	private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com";
	
	/**
	 * 红包发送
	 * @param data
	 * @param wxPayConfig
	 * @return
	 * @throws WxPayException 
	 */
	public WxPaySendRedpackResult redpack(String data,WxPayConfig wxPayConfig) throws WxPayException {
		WxPayService wxpayService = getWxpayService(wxPayConfig);
		WxPaySendRedpackRequest redpack = JSON.parseObject(data, WxPaySendRedpackRequest.class);
		//必须参数校验
		String openID = getHeader(Constants.HEADER_OPENID);
		if(StringUtils.isEmpty(redpack.getReOpenid()) && StringUtils.isEmpty(openID)) {
			throw new WxPayException("红包接收人openID不能为空！");
		}else {
			if(StringUtils.isNotBlank(openID)) {
				redpack.setReOpenid(openID);
			}
		}
		if(StringUtils.isEmpty(redpack.getClientIp())) {
			redpack.setClientIp(IPUtils.getIpAddress(getRequest()));
		}
		if(StringUtils.isEmpty(redpack.getMchBillNo())) {
			redpack.setMchBillNo(UUIDUtils.upperCaseUUID());
		}
		if(StringUtils.isEmpty(redpack.getWxAppid())) {
			redpack.setWxAppid(wxPayConfig.getAppId());
		}
		
		redpack.checkAndSign(wxPayConfig);

	    String url = PAY_BASE_URL + "/mmpaymkttransfers/sendredpack";
	    if (redpack.getAmtType() != null) {
	      //裂变红包
	      url = PAY_BASE_URL + "/mmpaymkttransfers/sendgroupredpack";
	    }

	    String responseContent = wxpayService.post(url, redpack.toXML(), true);
		//红包发送
		return fromXML(responseContent, WxPaySendRedpackResult.class);
	}
	
	/**
	 * 红包查询
	 * @param commondCode
	 * @param mchBillNo
	 * @param wxPayConfig
	 * @return
	 * @throws WxPayException
	 */
	public Result<?> redpackGet(String commondCode,String mchBillNo,WxPayConfig wxPayConfig) throws WxPayException {
		WxPayService wxPayService = getWxpayService(wxPayConfig);
		
		WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest();
	    request.setMchBillNo(mchBillNo);
	    request.setBillType(BillType.MCHT);
	    request.checkAndSign(wxPayConfig);

	    String url = PAY_BASE_URL + "/mmpaymkttransfers/gethbinfo";
	    String responseContent = wxPayService.post(url, request.toXML(), true);
	    WxPayRedpackQueryResult result = fromXML(responseContent, WxPayRedpackQueryResult.class);
	    result.checkResult(wxPayService, request.getSignType(), true);
		return Result.ok(result);
	}
	
	/**
	 * 支付成功通知
	 * @param data 微信通知参数
	 * @param wxPayConfig
	 * @return
	 */
	public String payNotify(String data,WxPayConfig wxPayConfig,BaseConfigBean configBean) {
		XStream xstream = XstreamUtils.getInstance(WxPayOrderNotifyResult.class);
	    xstream.processAnnotations(WxPayOrderNotifyResult.class);
	    xstream.registerConverter(new WxPayOrderNotifyResultConverter(xstream.getMapper(), xstream.getReflectionProvider()));
	    WxPayOrderNotifyResult wxPayOrderNotifyResult = (WxPayOrderNotifyResult) xstream.fromXML(data);
		logger.info("====pay notify data====\n{}",JSON.toJSON(wxPayOrderNotifyResult));
		String signKey = wxPayConfig.getMchKey();
		if(SignUtils.checkSign(wxPayOrderNotifyResult.toMap(),null, signKey)) {
			if(StringUtils.isNotEmpty(configBean.getPayNotifyUrl())) {
				//支付成功通知
				RequestUtils.post(configBean.getPayNotifyUrl(), JSON.toJSONString(wxPayOrderNotifyResult));
			}
			return WxPayNotifyResponse.success("");
		}
		return WxPayNotifyResponse.fail("验签失败！");
	}
	
	/**
	 * 退款成功通知
	 * @param data 微信通知参数
	 * @param wxPayConfig
	 * @return
	 */
	public String refundNotify(String data, WxPayConfig wxPayConfig, BaseConfigBean configBean) {
		String mchKey = wxPayConfig.getMchKey();
		try {
			WxPayRefundNotifyResult refundNotifyResult = fromXML(data, WxPayRefundNotifyResult.class);
			String reqInfoString = refundNotifyResult.getReqInfoString();
			final String keyMd5String = DigestUtils.md5Hex(mchKey).toLowerCase();
			SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(), "AES");
			Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, key);
			XStream xstream = XStreamInitializer.getInstance();
			xstream.processAnnotations(ReqInfo.class);
			ReqInfo reqInfo = (ReqInfo) xstream.fromXML(new String(cipher.doFinal(Base64.decodeBase64(reqInfoString))));
			refundNotifyResult.setReqInfo(reqInfo);
			logger.info("=================refund notify data========================\n{}",JSON.toJSON(refundNotifyResult));
			if(StringUtils.isNotEmpty(configBean.getRefundNotifyUrl())) {
				RequestUtils.post(configBean.getRefundNotifyUrl(), JSON.toJSONString(refundNotifyResult));
			}
			return WxPayNotifyResponse.success("");
		} catch (Exception e) {
			logger.error("refund notify fail", e);
		}
		return WxPayNotifyResponse.fail("参数校验失败");
	}
	
	/**
	 * 调用微信统一下单接口
	 * @param orderData
	 * @param wxPayConfig
	 * @return
	 */
	public String unifiedOrder(String orderData,WxPayConfig wxPayConfig) {
		WxPayUnifiedOrderRequest request = JSON.parseObject(orderData, WxPayUnifiedOrderRequest.class);
		WxPayService wxpayService = getWxpayService(wxPayConfig);
		try {
//			if(StringUtils.isEmpty(request.getTimeStart())) {//支付默认5分钟有效，5分钟后订单过期
//				Long now = System.currentTimeMillis();
//				request.setTimeStart(DateUtils.format(new Date(now), "yyyyMMddHHmmss"));
//				request.setTimeExpire(DateUtils.format(new Date(now+5*60*1000), "yyyyMMddHHmmss"));
//			}
			//trade_type为JSAPI支付需要校验openID有无传递进来
			if("JSAPI".equals(request.getTradeType()) 
					&& StringUtils.isEmpty(request.getOpenid()) && StringUtils.isEmpty(getHeader(Constants.HEADER_OPENID))) {
				return JSON.toJSONString(Result.error("微信JSAPI类型的支付openID必须！"));
			}else {
				if(StringUtils.isNotEmpty(getHeader(Constants.HEADER_OPENID))) {
					request.setOpenid(getHeader(Constants.HEADER_OPENID));
				}
			}
			request.setSpbillCreateIp(IPUtils.getIpAddress(getRequest()));
			Object result = createOrder(wxpayService, request, wxPayConfig);
			return JSON.toJSONString(Result.ok(result));
		} catch (Exception e) {
			logger.error("unifiedOrder fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
	
	public static <T extends BaseWxPayResult> T fromXML(String xmlString, Class<T> clz) {
	    XStream xstream = XstreamUtils.getInstance(PayService.class);
	    xstream.processAnnotations(clz);
	    T result = (T) xstream.fromXML(xmlString);
	    result.setXmlString(xmlString);
	    return result;
	}
	
	public <T> T createOrder(WxPayService wxPayService,WxPayUnifiedOrderRequest request,WxPayConfig wxPayConfig) throws WxPayException {
		request.checkAndSign(wxPayConfig);

	    String url = PAY_BASE_URL + "/pay/unifiedorder";
	    String responseContent = wxPayService.post(url, request.toXML(), false);
	    WxPayUnifiedOrderResult unifiedOrderResult = fromXML(responseContent, WxPayUnifiedOrderResult.class);
	    unifiedOrderResult.checkResult(wxPayService, request.getSignType(), true);
	    String prepayId = unifiedOrderResult.getPrepayId();
	    if (StringUtils.isBlank(prepayId)) {
	      throw new WxPayException(String.format("无法获取prepay id，错误代码： '%s'，信息：%s。",
	        unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes()));
	    }

	    String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
	    String nonceStr = String.valueOf(System.currentTimeMillis());
	    switch (request.getTradeType()) {
	      case TradeType.MWEB: {
	        return (T) new WxPayMwebOrderResult(unifiedOrderResult.getMwebUrl());
	      }

	      case TradeType.NATIVE: {
	        return (T) new WxPayNativeOrderResult(unifiedOrderResult.getCodeURL());
	      }

	      case TradeType.APP: {
	        // APP支付绑定的是微信开放平台上的账号，APPID为开放平台上绑定APP后发放的参数
	        String appId = unifiedOrderResult.getAppid();
	        if (StringUtils.isNotEmpty(unifiedOrderResult.getSubAppId())) {
	          appId = unifiedOrderResult.getSubAppId();
	        }

	        Map<String, String> configMap = new HashMap<>(8);
	        // 此map用于参与调起sdk支付的二次签名,格式全小写，timestamp只能是10位,格式固定，切勿修改
	        String partnerId;
	        if (StringUtils.isEmpty(request.getMchId())) {
	          partnerId = wxPayConfig.getMchId();
	        } else {
	          partnerId = request.getMchId();
	        }

	        configMap.put("prepayid", prepayId);
	        configMap.put("partnerid", partnerId);
	        String packageValue = "Sign=WXPay";
	        configMap.put("package", packageValue);
	        configMap.put("timestamp", timestamp);
	        configMap.put("noncestr", nonceStr);
	        configMap.put("appid", appId);

	        final WxPayAppOrderResult result = WxPayAppOrderResult.builder()
	          .sign(SignUtils.createSign(configMap, null, wxPayConfig.getMchKey(), null))
	          .prepayId(prepayId)
	          .partnerId(partnerId)
	          .appId(appId)
	          .packageValue(packageValue)
	          .timeStamp(timestamp)
	          .nonceStr(nonceStr)
	          .build();
	        return (T) result;
	      }

	      case TradeType.JSAPI: {
	        String signType = SignType.MD5;
	        String appid = unifiedOrderResult.getAppid();
	        if (StringUtils.isNotEmpty(unifiedOrderResult.getSubAppId())) {
	          appid = unifiedOrderResult.getSubAppId();
	        }

	        WxPayMpOrderResult payResult = WxPayMpOrderResult.builder()
	          .appId(appid)
	          .timeStamp(timestamp)
	          .nonceStr(nonceStr)
	          .packageValue("prepay_id=" + prepayId)
	          .signType(signType)
	          .build();

	        payResult.setPaySign(SignUtils.createSign(payResult, signType, wxPayConfig.getMchKey(), null));
	        return (T) payResult;
	      }
	      default: {
	        throw new WxPayException("该交易类型暂不支持");
	      }
	    }

	  }
	
	/**
	 * 订单查询
	 * @param wxPayConfig
	 * @param outTradeNo
	 * @return
	 */
	public String orderQuery(WxPayConfig wxPayConfig,String outTradeNo,String transactionId) {
		WxPayService wxpayService = getWxpayService(wxPayConfig);
		try {
			WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
		    request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
		    request.setTransactionId(StringUtils.trimToNull(transactionId));
		    request.checkAndSign(wxPayConfig);
		    String url = "https://api.mch.weixin.qq.com/pay/orderquery";
		    String responseContent = wxpayService.post(url, request.toXML(), false);
		    WxPayOrderQueryResult wxPayOrderQueryResult = fromXML(responseContent, WxPayOrderQueryResult.class);
		    return JSON.toJSONString(Result.ok(wxPayOrderQueryResult));
		} catch (WxPayException e) {
			logger.error("order query fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
	
	/**
	 * 订单关闭
	 * @param wxPayConfig
	 * @param outTradeNo
	 * @return
	 */
	public String orderClose(WxPayConfig wxPayConfig, String outTradeNo) {
		WxPayService wxpayService = getWxpayService(wxPayConfig);
		try {
			if (StringUtils.isBlank(outTradeNo)) {
				throw new WxPayException("out_trade_no不能为空");
			}
			WxPayOrderCloseRequest request = new WxPayOrderCloseRequest();
			request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
			request.checkAndSign(wxPayConfig);
		    String url = PAY_BASE_URL + "/pay/closeorder";
		    String responseContent = wxpayService.post(url, request.toXML(), false);
			WxPayOrderCloseResult closeResult = fromXML(responseContent, WxPayOrderCloseResult.class);
			if ("SUCCESS".equals(closeResult.getResultCode())) {
				return JSON.toJSONString(Result.ok());
			}
			return JSON.toJSONString(Result.error(closeResult.getErrCodeDes()));
		} catch (WxPayException e) {
			logger.error("order close fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
	
	/**
	 * 退款申请
	 * @param wxPayConfig
	 * @param refundData
	 * @return
	 */
	public String refund(WxPayConfig wxPayConfig,String refundData) {
		WxPayRefundRequest request = JSON.parseObject(refundData, WxPayRefundRequest.class);
		WxPayService wxpayService = getWxpayService(wxPayConfig);
		try {
			request.checkAndSign(wxPayConfig);

		    String url = PAY_BASE_URL + "/secapi/pay/refund";
		    String responseContent = wxpayService.post(url, request.toXML(), true);
		    WxPayRefundResult refundResult = fromXML(responseContent, WxPayRefundResult.class);
		    refundResult.composeRefundCoupons();
		    refundResult.checkResult(wxpayService, request.getSignType(), true);
			return JSON.toJSONString(Result.ok(refundResult));
		} catch (WxPayException e) {
			logger.error("refund fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
	
	/**
	 * 退款查询
	 * @param wxPayConfig
	 * 以下参数四选一
	 * @param transactionId
	 * @param outTradeNo
	 * @param outRefundNo
	 * @param refundId
	 * @return
	 */
	public String refundQuery(WxPayConfig wxPayConfig,String transactionId, String outTradeNo, String outRefundNo, String refundId) {
		WxPayService wxpayService = getWxpayService(wxPayConfig);
		try {
			WxPayRefundQueryRequest request = new WxPayRefundQueryRequest();
		    request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
		    request.setTransactionId(StringUtils.trimToNull(transactionId));
		    request.setOutRefundNo(StringUtils.trimToNull(outRefundNo));
		    request.setRefundId(StringUtils.trimToNull(refundId));
			
		    request.checkAndSign(wxPayConfig);

		    String url = PAY_BASE_URL + "/pay/refundquery";
		    String responseContent = wxpayService.post(url, request.toXML(), false);
		    WxPayRefundQueryResult result = fromXML(responseContent, WxPayRefundQueryResult.class);
		    result.composeRefundRecords();
		    result.checkResult(wxpayService, request.getSignType(), true);
			return JSON.toJSONString(Result.ok(result));
		} catch (WxPayException e) {
			logger.error("refund query fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
	
	/**
	 * 对账单下载
	 * @param wxPayConfig
	 * @param billDate
	 * @param billType
	 * @param tarType
	 * @param deviceInfo
	 * @return
	 */
	public String dowloadBill(WxPayConfig wxPayConfig,String billDate, String billType, String tarType, String deviceInfo) {
		WxPayService wxpayService = getWxpayService(wxPayConfig);
		try {
			WxPayBillResult billResult = wxpayService.downloadBill(billDate, billType, tarType, deviceInfo);
			return JSON.toJSONString(Result.ok(billResult));
		} catch (WxPayException e) {
			logger.error("dowload bill fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
	
	/**
	 * 企业付款到微信个人零钱账户
	 * @param wxPayConfig
	 * @param data
	 * @return
	 */
	public String entPay(WxPayConfig wxPayConfig,String data) {
		EntPayRequest request = JSON.parseObject(data, EntPayRequest.class);
		request.setMchAppid(wxPayConfig.getAppId());
		request.setSpbillCreateIp(IPUtils.getIpAddress(getRequest()));
		request.setMchId(wxPayConfig.getMchId());
		String openid = getHeader(Constants.HEADER_OPENID);
		if(StringUtils.isEmpty(request.getOpenid()) && StringUtils.isEmpty(openid)) {
			return JSON.toJSONString(Result.error("用户标识openid必须！！！"));
		}else {
			if(StringUtils.isNotEmpty(openid)) {
				request.setOpenid(openid);
			}
		}
		String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
		WxPayService wxpayService = getWxpayService(wxPayConfig);
		try {
			request.checkAndSign(wxPayConfig);
			String res = wxpayService.post(url, request.toXML(), true);
			Map<String, String> map = XMLConverUtil.convertToMap(res);
			return JSON.toJSONString(Result.ok(map));
		} catch (WxPayException e) {
			logger.error("ent pay fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
	
	/**
	 * 企业付款到微信个人零钱账户付款记录查询
	 * @param wxPayConfig
	 * @param partnerTradeNo
	 * @return
	 */
	public String queryEntPay(WxPayConfig wxPayConfig,String partnerTradeNo) {
		WxPayService wxPayService = getWxpayService(wxPayConfig);
		try {
			EntPayQueryRequest request = new EntPayQueryRequest();
		    request.setPartnerTradeNo(partnerTradeNo);
		    request.checkAndSign(wxPayConfig);

		    String url = PAY_BASE_URL + "/mmpaymkttransfers/gettransferinfo";
		    String responseContent = wxPayService.post(url, request.toXML(), true);
		    EntPayQueryResult result = fromXML(responseContent, EntPayQueryResult.class);
		    result.checkResult(wxPayService, request.getSignType(), true);
			return JSON.toJSONString(Result.ok(result));
		} catch (WxPayException e) {
			logger.error("ent pay query fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
	
	/**
	 * 企业付款至银行卡账号
	 * @param wxPayConfig
	 * @param data
	 * @return
	 */
	public String payBank(WxPayConfig wxPayConfig,String data) {
		EntPayBankRequest request = JSON.parseObject(data, EntPayBankRequest.class);
		WxPayService wxPayService = getWxpayService(wxPayConfig);
		EntPayService entPayService = new EntPayServiceImpl(wxPayService);
		try {
			File publicKeyFile = this.buildPublicKeyFile(entPayService);
		    request.setEncBankNo(this.encryptRSA(publicKeyFile, request.getEncBankNo()));
		    request.setEncTrueName(this.encryptRSA(publicKeyFile, request.getEncTrueName()));
		    publicKeyFile.deleteOnExit();

		    request.checkAndSign(wxPayConfig);

		    String url = PAY_BASE_URL + "/mmpaysptrans/pay_bank";
		    String responseContent = wxPayService.post(url, request.toXML(), true);
		    EntPayBankResult result = fromXML(responseContent, EntPayBankResult.class);
		    result.checkResult(wxPayService, request.getSignType(), true);
			
			return JSON.toJSONString(Result.ok(result));
		} catch (WxPayException e) {
			logger.error("pay bank fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
	
	private String encryptRSA(File publicKeyFile, String srcString) throws WxPayException {
	    try {
	      Security.addProvider(new BouncyCastleProvider());
	      Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
	      try (PEMParser reader = new PEMParser(new FileReader(publicKeyFile))) {
	        final PublicKey publicKey = new JcaPEMKeyConverter().setProvider("BC")
	          .getPublicKey((SubjectPublicKeyInfo) reader.readObject());

	        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
	        byte[] encrypt = cipher.doFinal(srcString.getBytes());
	        return Base64.encodeBase64String(encrypt);
	      }
	    } catch (Exception e) {
	      throw new WxPayException("加密出错", e);
	    }
	  }

	  private File buildPublicKeyFile(EntPayService entPayService) throws WxPayException {
	    try {
	      String publicKeyStr = entPayService.getPublicKey();
	      Path tmpFile = Files.createTempFile("payToBank", ".pem");
	      Files.write(tmpFile, publicKeyStr.getBytes());
	      return tmpFile.toFile();
	    } catch (Exception e) {
	      throw new WxPayException("生成加密公钥文件时发生异常", e);
	    }
	  }
	
	/**
	 * 企业付款至银行卡的记录查询
	 * @param wxPayConfig
	 * @param partnerTradeNo
	 * @return
	 */
	public String queryPayBank(WxPayConfig wxPayConfig,String partnerTradeNo) {
		WxPayService wxPayService = getWxpayService(wxPayConfig);
		try {
			EntPayBankQueryRequest request = new EntPayBankQueryRequest();
		    request.setPartnerTradeNo(partnerTradeNo);
		    request.checkAndSign(wxPayConfig);

		    String url = PAY_BASE_URL + "/mmpaysptrans/query_bank";
		    String responseContent = wxPayService.post(url, request.toXML(), true);
		    EntPayBankQueryResult result = fromXML(responseContent, EntPayBankQueryResult.class);
		    result.checkResult(wxPayService, request.getSignType(), true);
			
			return JSON.toJSONString(Result.ok(result));
		} catch (WxPayException e) {
			logger.error("query bank pay fail", e);
			return JSON.toJSONString(Result.error(e.getMessage()));
		}
	}
}
